import java.net.*;
import java.io.*;
import java.util.*;

/** ServerTalk5.java and LocalTalk2.java:
   ServerTalk5.java improves ServerTalk4.java by adding the following
 features:
	1. Two threads, SendAgent ad ReceiveAgent, will be used, one for
	   sending message to clients and the other one for receiving
	   information from clients. One benefit of two threads is that
	   server and clients can have different speeds of sending and
	   receiving messages.
	2. Try skip the input streams that have no message available. 
*/
   
public class ServerTalk5 {

   public static void main(String args[] ) {
      ObjectInputStream in;
      InputStream inStm;
      ObjectOutputStream out;
      Vector vIn = new Vector();
      Vector vInStm = new Vector();
      Vector vOut = new Vector();

      try {
        ServerSocket ssk = new ServerSocket(8900);
	Socket	     sk;
	SendAgent	     sendAgent = new SendAgent(vOut ) ;
	ReceiveAgent	     receiveAgent = new ReceiveAgent(vIn, vInStm) ;
	sendAgent.start(); receiveAgent.start();

        while ( true ) {
		sk = ssk.accept();
		out = new ObjectOutputStream( sk.getOutputStream());
		inStm = sk.getInputStream();
		in = new ObjectInputStream( inStm );
		vInStm.add( inStm ); vIn.add(in); vOut.add(out);
		System.out.println("Size of vOut = " + vOut.size() +
				   "  Size of vIn = " + vIn.size()   );
        }
      } catch (Exception e) { e.printStackTrace(); }
   }
}

class SendAgent extends Thread {

   Vector vOut;

   public SendAgent(Vector vOut) { this.vOut = vOut; }

   public void run() {

      try {
	int mNum = 1;
	String message;

	ObjectInputStream in;
	ObjectOutputStream out;

	int i = 0;
	while ( true ) {
	  try {
		if ( vOut.size() < 1 ) continue;

		message = "Server message " + (mNum ++);
		i = (int) (Math.random() * vOut.size());
		out = (ObjectOutputStream) vOut.get(i);
		out.writeObject( message );
		out.flush();
	  } catch (IOException e) { vOut.remove(i); }
	    sleep( (int)(Math.random() * 2000) + 500);
	}
      } catch (Exception e) { e.printStackTrace(); }
   }
}

class ReceiveAgent extends Thread {
   Vector vIn, vInStm;

   public ReceiveAgent(Vector vIn, Vector vInStm ) { this.vIn = vIn; this.vInStm = vInStm; }

   public void run() {
      try {
	int mNum = 1;
	String message;

	ObjectInputStream in;
	InputStream inStm;

	while ( true ) {
	  int i = 0 ;
	  try {
	    for ( i = 0; i < vIn.size(); i++ ) {
		in = (ObjectInputStream) vIn.get(i); inStm = (InputStream) vInStm.get(i);
		if ( inStm.available() > 0 ) {
			message = (String) in.readObject();
			System.out.println("Message received by server: " + message);
		} else System.out.println("Clinet " + (i+1) + " has no message in this run");
	    }
	    sleep(500);
	  } catch (IOException e) { vIn.remove(i); vInStm.remove(i); }
	}
      } catch (Exception e) { e.printStackTrace(); }
   }
}


